package com.luoran.bartalks.action;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.beetl.sql.core.engine.PageQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.alibaba.fastjson.JSONObject;
import com.luoran.bartalks.core.UserContext;
import com.luoran.bartalks.core.ext.Pageable;
import com.luoran.bartalks.entity.BaseInfo;
import com.luoran.bartalks.entity.biz.BtMateriel;
import com.luoran.bartalks.entity.biz.BtMaterielType;
import com.luoran.bartalks.entity.biz.BtPackingListMateriel;
import com.luoran.bartalks.service.IBtMaterielService;
import com.luoran.bartalks.service.IBtMaterielTypeService;
import com.luoran.bartalks.service.IBtPackingListMaterielService;
import com.luoran.bartalks.utils.EnumScanType;
import com.luoran.bartalks.utils.UUID;

@Controller
@RequestMapping("/materiel")
public class BtMaterieAction implements Pageable {

	@Autowired
	private IBtMaterielService materielService;

	@Autowired
	private IBtMaterielTypeService materielTypeService;

	@Autowired
	private IBtPackingListMaterielService packingListMaterielService;

	private static final Logger log = LoggerFactory.getLogger(BtPositionAction.class);

	/**
	 * 物料信息列表页面
	 */
	@RequestMapping
	public String queryMateriel() {
		log.info("跳转到>>物料信息列表页面");
		return "basics/materiel-list";
	}

	// 分页
	public PageQuery<? extends BaseInfo> getQueryList(PageQuery<? extends BaseInfo> pageQuery) {
		log.info("获取物料管理列表数据,page:" + pageQuery.getPageNumber() + "size:" + pageQuery.getPageSize());
		@SuppressWarnings("unchecked")
		Map<String, String> map = (Map<String, String>) pageQuery.getParas();
		map.put("companyId", UserContext.get().getCompanyId());// 添加查询参数（公司ID）
		if (StringUtils.isEmpty(pageQuery.getOrderBy())) {
			pageQuery.setOrderBy("create_time DESC");
		}
		return materielService.getQueryList(pageQuery);
	}

	// 新增物料
	@PostMapping("/addMateriel")
	@ResponseBody
	public JSONObject addMaterielType(BtMateriel btMateriel) {
		log.info("新增物料>>");

		JSONObject res = new JSONObject();
		res = check(btMateriel);
		if (!res.getBooleanValue("state")) {
			return res;
		}

		log.info("检测物料编码是否被占用>>>>");
		// 根据物料编码查询物料
		BtMateriel materiel = materielService.getMaterielByMaterielCode(btMateriel.getMaterielCode(),
				UserContext.get().getCompanyId());
		if (materiel != null) {
			log.info("物料编码已被占用<<<<");
			res.put("flag", false);
			res.put("msg", "物料编码'" + btMateriel.getMaterielCode() + "'已被占用");
			return res;
		}
		btMateriel.setCompanyId(UserContext.get().getCompanyId());
		btMateriel.setCreateTime(new Date());
		btMateriel.setQrcode("0");
		btMateriel.setStatus(0);// 默认状态
		btMateriel.setId(UUID.get());
		String id = materielService.addBtMateriel(btMateriel);
		if (id != null) {
			res.put("flag", true);
			res.put("msg", "操作成功");
			return res;
		} else {
			res.put("flag", false);
			res.put("msg", "操作失败,请重试");
			return res;
		}
	}

	// 根据id获取物料信息
	@RequestMapping("getMaterielById/{id}")
	@ResponseBody
	public JSONObject getMaterielInfo(@PathVariable("id") String id) {
		log.info("根据 Id 获取物料信息>>>");
		JSONObject res = new JSONObject();
		BtMateriel btMateriel = materielService.getBtMateriel(id);
		res.put("obj", btMateriel);
		res.put("state", true);
		return res;
	}

	// 编辑
	@PostMapping("/editMateriel")
	@ResponseBody
	public JSONObject editMaterielType(BtMateriel btMateriel) {
		log.info("更新物料信息>>");
		JSONObject res = new JSONObject();
		res = check(btMateriel);
		if (!res.getBooleanValue("state")) {
			return res;
		} else {
			int count = materielService.updateMaterielById(btMateriel);
			if (count == 1) {
				res.put("state", true);
				res.put("msg", "操作成功");
				return res;
			} else {
				res.put("state", false);
				res.put("msg", "操作失败");
				return res;
			}
		}
	}

	// 删除
	@RequestMapping("/deleteMateriel/{id}")
	@ResponseBody
	public JSONObject deleteMateriel(@PathVariable("id") String id) {
		log.info("删除物料信息数据>>");
		JSONObject res = new JSONObject();
		BtMateriel btMateriel = new BtMateriel();
		btMateriel.setId(id);
		btMateriel.setStatus(1);
		int count = materielService.updateMaterielById(btMateriel);
		if (count == 1) {
			res.put("state", true);
			res.put("msg", "操作成功");
			return res;
		} else {
			res.put("state", false);
			res.put("msg", "操作失败");
			return res;
		}
	}

	// 检测当前公司是否有物料类型.
	@RequestMapping("/hasMaterielType")
	@ResponseBody
	public JSONObject hasMaterielTypeByCompanyId() {
		JSONObject result = new JSONObject();
		log.info("检测当前公司是否有物料分类>>>>>");
		List<BtMaterielType> materielTypes = materielTypeService
				.getMaterielTypeByCompanyId(UserContext.get().getCompanyId());
		if (materielTypes.size() == 0) {// 无分类
			log.info("未找到物料分类,可直接新增物料<<<<");
			result.put("flag", false);
			result.put("msg", "未找到物料分类");
			return result;
		} else {
			log.info("找到物料分类,需先选择分类,才能新增物料<<<<");
			result.put("flag", true);
			result.put("msg", "请先选择分类");
			return result;
		}
	}

	// 修改,删除需要校验是否被箱单引用,
	@RequestMapping("/checkMateriel/{materielCode}")
	@ResponseBody
	public JSONObject checkMateriel(@PathVariable("materielCode") String materielCode) {
		JSONObject result = new JSONObject();
		log.info("检测当前操作物料是否被箱单引用>>>物料编码[{}]", materielCode);
		// 根据物料编码查询箱单.
		List<BtPackingListMateriel> packingListMateriel = packingListMaterielService.hasMateriel(materielCode,
				UserContext.get().getCompanyId());
		if (packingListMateriel != null && packingListMateriel.size() != 0) {
			log.info("当前物料已被引用<<<");
			result.put("flag", true);
			result.put("msg", "当前物料已被引用,无法操作");
			return result;
		} else {
			result.put("flag", false);
			return result;
		}

	}

	// 物料模板下载
	@GetMapping("/download")
	public void downloadFile(String fileName, HttpServletResponse res) {
		InputStream fis = this.getClass().getResourceAsStream(fileName);
		if (fis == null) {
			try {
				res.setContentType("text/html;charset=utf-8");
				res.getWriter().write("模板资源不存在,请联系管理员!");
				res.flushBuffer();
			} catch (IOException e) {
			}
			return;
		}
		res.setContentType("application/octet-stream");
		try {
			res.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
		}
		try {
			IOUtils.copy(fis, res.getOutputStream());
			res.flushBuffer();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
				}
			}
		}
	}

	// 物料导入
	@RequestMapping("/importExcel")
	@ResponseBody
	public JSONObject materielImport(MultipartHttpServletRequest request) {
		JSONObject result = new JSONObject();
		for (Iterator<String> it = request.getFileNames(); it.hasNext();) {
			String fname = it.next();
			if (!StringUtils.isEmpty(fname)) {
				MultipartFile mulFile = request.getFile(fname);
				if (mulFile != null) {
					try {
						InputStream is = mulFile.getInputStream();
						try {
							// 得到工作簿对象
							HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
							// 得到工作表对象
							HSSFSheet sheet = hssfWorkbook.getSheetAt(0);
							result = checkExcelTemplate(sheet);// 校验模板是否正确
							if (!result.getBooleanValue("flag")) {
								return result;
							}
							result = readExcel(sheet);// 读取Excel并插入数据库
							if (!result.getBooleanValue("flag")) {
								return result;
							}
						} finally {
							is.close();
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		result.put("flag", true);
		result.put("msg", "导入成功!");
		return result;
	}

	// 读取Excel的方法
	public static String getStringValueFromCell(Cell cell) {
		SimpleDateFormat sFormat = new SimpleDateFormat("MM/dd/yyyy");
		DecimalFormat decimalFormat = new DecimalFormat("#.#");
		String cellValue = "";
		if (cell == null) {
			return cellValue;
		} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
			cellValue = cell.getStringCellValue();
		} else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
			if (HSSFDateUtil.isCellDateFormatted(cell)) {
				double d = cell.getNumericCellValue();
				Date date = HSSFDateUtil.getJavaDate(d);
				cellValue = sFormat.format(date);
			} else {
				cellValue = decimalFormat.format((cell.getNumericCellValue()));
			}
		} else if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
			cellValue = "";
		} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
			cellValue = String.valueOf(cell.getBooleanCellValue());
		} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
			cellValue = "";
		} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
			cellValue = cell.getCellFormula().toString();
		}
		return cellValue;
	}

	// 判断输入信息是否合法
	private JSONObject check(BtMateriel btMateriel) {

		JSONObject res = new JSONObject();
		String regex = "^[0-9a-zA-Z]{1,20}$";
		if (!btMateriel.getMaterielCode().matches(regex)) {
			res.put("msg", "物料编码不合法");
			res.put("state", false);
			return res;
		}
		if (StringUtils.isEmpty(btMateriel.getMaterielName())) {
			res.put("msg", "物料名称不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getValue())) {
			res.put("msg", "物料价值不可以为空");
			res.put("state", false);
			return res;
		}
		if (StringUtils.isEmpty(btMateriel.getEmptyWeight())) {
			res.put("msg", "物料净重不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getGrossWeight())) {
			res.put("msg", "物料毛重不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getLength())) {
			res.put("msg", "物料长度不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getWidth())) {
			res.put("msg", "物料宽度不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getHeight())) {
			res.put("msg", "物料高度不可以为空");
			res.put("state", false);
			return res;
		}

		if (StringUtils.isEmpty(btMateriel.getVolume())) {
			res.put("msg", "物料体积不可以为空");
			res.put("state", false);
			return res;
		}
		res.put("state", true);
		return res;
	}

	// 校验Excel模板是否正确
	private JSONObject checkExcelTemplate(HSSFSheet sheet) {// 工作表对象

		JSONObject result = new JSONObject();
		// 获取第一行标题
		HSSFRow title = sheet.getRow(0);
		log.info("校验模板是否正确>>>>>");
		for (int i = 0; i < title.getLastCellNum(); i++) {
			HSSFCell hssfCell = title.getCell(i);// 获得单元格信息
			if (i == 0) {
				if (!"物料名称".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}

			if (i == 1) {
				if (!"物料编码".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}

			if (i == 2) {
				if (!"长度(cm)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 3) {
				if (!"宽度(cm)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 4) {
				if (!"高度(cm)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 5) {
				if (!"体积(cm³)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 6) {
				if (!"净重(kg)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 7) {
				if (!"毛重(kg)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
			if (i == 8) {
				if (!"价值(元)".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}

			if (i == 9) {
				if (!"所属分类编码".equals(getStringValueFromCell(hssfCell))) {
					result.put("flag", false);
					result.put("msg", "Excel文件与模板不符,请重新下载!");
					return result;
				}
			}
		}
		result.put("flag", true);
		log.info("模板校验完成,模板正确<<<");
		return result;

	}

	// 读取Excel并插入数据库
	private JSONObject readExcel(HSSFSheet sheet) {
		JSONObject result = new JSONObject();

		log.info("读取Excel文件中的物料信息>>>");
		// 从第二行开始获取 一直到最后一行 得到物料信息.
		for (int j = 1; j <= sheet.getLastRowNum(); j++) {

			log.info("跳过标题,读取第" + (j + 1) + "行信息>>");
			// 遍历每一行 得到每一行记录
			HSSFRow row = sheet.getRow(j);

			log.info("校验文件第" + (j + 1) + "行必填项是否填写>>>");
			// 检测每列物料名称是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(0)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料名称为空");
				return result;
			}
			// 检测每列物料编码是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(1)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料编码为空");
				return result;
			}
			// 检测每列物料长度是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(2)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料长度为空");
				return result;
			}
			// 检测每列物料宽度是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(3)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料宽度为空");
				return result;
			}
			// 检测每列物料高度是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(4)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料高度为空");
				return result;
			}
			// 检测每列物料体积是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(5)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料体积为空");
				return result;
			}
			// 检测每列物料净重是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(6)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料净重为空");
				return result;
			}
			// 检测每列物料毛重是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(7)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料毛重为空");
				return result;
			}
			// 检测每列物料价值是否为空
			if (StringUtils.isEmpty(getStringValueFromCell(row.getCell(8)))) {
				result.put("flag", false);
				result.put("msg", "导入出错,第" + (j + 1) + "行物料价值为空");
				return result;
			}

			log.info("第" + (j + 1) + "行必填项校验完成<<<");
			// 检测物料编码是否被占用
			log.info("检测物料编码是否被占用>>>");
			// 根据物料编码查询物料
			BtMateriel persistentMateriel = materielService.getMaterielByMaterielCode(
					getStringValueFromCell(row.getCell(1)), UserContext.get().getCompanyId());
			if (persistentMateriel != null) {
				log.info("第" + (j + 1) + "行物料编码已被占用>>[{}]", getStringValueFromCell(row.getCell(1)));
				result.put("flag", false);
				result.put("msg", "第" + (j + 1) + "行物料编码'" + getStringValueFromCell(row.getCell(1)) + "'已被占用");
				return result;
			} else {
				log.info("第" + (j + 1) + "行物料编码未被占用>>[{}]", getStringValueFromCell(row.getCell(1)));
			}

			// 物料对象接收物料信息
			BtMateriel materiel = new BtMateriel();

			materiel.setId(UUID.get());
			materiel.setMaterielName(getStringValueFromCell(row.getCell(0)));// 每列的第一格.物料名称
			materiel.setMaterielCode(getStringValueFromCell(row.getCell(1)));// 编码
			materiel.setLength(new BigDecimal(getStringValueFromCell(row.getCell(2))));// 长度
			materiel.setWidth(new BigDecimal(getStringValueFromCell(row.getCell(3))));// 款
			materiel.setHeight(new BigDecimal(getStringValueFromCell(row.getCell(4))));// 高
			materiel.setVolume(new BigDecimal(getStringValueFromCell(row.getCell(5))));// 体积
			materiel.setEmptyWeight(new BigDecimal(getStringValueFromCell(row.getCell(6))));// 净重
			materiel.setGrossWeight(new BigDecimal(getStringValueFromCell(row.getCell(7))));// 毛重
			materiel.setValue(new BigDecimal(getStringValueFromCell(row.getCell(8))));// 价值

			log.info("检测文件中第" + (j + 1) + "行是否填写物料分类编码>>>");
			if (!StringUtils.isEmpty(getStringValueFromCell(row.getCell(9)))) {
				log.info("第" + (j + 1) + "行已填写物料分类编码<<");
				// 通过物料分类编码查询物料分类是否存在
				log.info("检测物料分类编码对于的物料分类是否存在>>>>");
				BtMaterielType persistentMaterielType = materielTypeService.getMaterielTypeByTypeCode(
						getStringValueFromCell(row.getCell(9)), UserContext.get().getCompanyId());
				if (persistentMaterielType != null) {// 存在
					log.info("物料分类存在<<<");
					materiel.setTypeId(persistentMaterielType.getId());// 分类id
					materiel.setTypeCode(persistentMaterielType.getTypeCode());// 分类编码
					materiel.setTypeName(persistentMaterielType.getTypeName());// 分类名称
					materiel.setLongCode(
							persistentMaterielType.getLongCode() + "!" + getStringValueFromCell(row.getCell(1)));
				} else {
					log.info("物料分类不存在<<<");
				}
			} else {
				log.info("第" + (j + 1) + "行未填写物料分类编码<<");
			}
			materiel.setCompanyId(UserContext.get().getCompanyId());// 设置所属公司公司ID
			materiel.setCreateTime(new Date());
			materiel.setQrcode(EnumScanType.MATERIEL.getValue() + ";" + materiel.getId());// 二维码
			materiel.setStatus(0);

			// 插入
			String materielId = materielService.addBtMateriel(materiel);

			if (materielId == null) {
				result.put("flag", false);
				result.put("msg", "导入失败,请重试!");
				return result;
			}
			log.info("第" + (j + 1) + "行物料记录导入成功<<<");
		}
		result.put("flag", true);
		return result;
	}

}
